package com.example.demo.config;

import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.toolkit.GlobalConfigUtils;
import com.example.demo.util.GlobalUtil;
import com.example.demo.view.ModelView;
import com.example.demo.view.ViewScan;
import lombok.SneakyThrows;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.GenericTypeResolver;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.core.type.filter.TypeFilter;
import org.springframework.stereotype.Component;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Collectors;

@Configuration
public class StartRunner implements ApplicationRunner, ImportBeanDefinitionRegistrar {

    @Autowired
    private SqlSessionFactory sessionFactory;

    private static final Set<String> scanPackage = new HashSet<>();

    @Override
    public void run(ApplicationArguments args) throws Exception {
        //获取所有Mapper名
        Set<String> mapperClassNames = GlobalConfigUtils.getMapperRegistryCache(sessionFactory.getConfiguration());
        mapperClassNames.forEach(name -> {
            try {
                //获取Mapper Class
                Class clazz = Class.forName(name.replace("interface", "").trim());
                //从Mapper获取实体Entity
                Class gen = GenericTypeResolver.resolveTypeArgument(clazz,BaseMapper.class);
                GlobalUtil.mapperClassMap.put(StringUtils.uncapitalize(gen.getSimpleName()),clazz);
                GlobalUtil.entityClassMap.put(StringUtils.uncapitalize(gen.getSimpleName()),gen);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        });
        //扫描所有的view包 获取ViewJson
        initAllJsonView();
    }

    void initAllJsonView(){
        List<JSONArray> views = new ArrayList<>();
        scanPackages(scanPackage.toArray(new String[0]),new TypeFilter[]{new AnnotationTypeFilter(ModelView.class)}, aClass -> {
            GlobalUtil.viewMap.put(StringUtils.uncapitalize(aClass.getSimpleName()),GlobalUtil.toViewJson(aClass));
        });
    };

    @Override
    @SneakyThrows
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
       Class clazz = ClassUtils.forName(importingClassMetadata.getClassName(),ClassUtils.getDefaultClassLoader());
       ViewScan viewScan =  (ViewScan)clazz.getAnnotation(ViewScan.class);
       if(viewScan.packages()==null||viewScan.packages().length==0){
           scanPackage.add(clazz.getPackage().getName());
       }else {
           scanPackage.addAll(Arrays.asList(viewScan.packages()));
       }
    }

    private void scanPackages(String[] packages, TypeFilter[] typeFilters, Consumer<Class> consumer){
        ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
        for (TypeFilter typeFilter:typeFilters){
            scanner.addIncludeFilter(typeFilter);
        }
        for (String pack:packages){
            for (BeanDefinition beanDefinition:scanner.findCandidateComponents(pack)){
                Class clazz = null;
                try {
                    clazz = Class.forName(beanDefinition.getBeanClassName());
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
                consumer.accept(clazz);
            }
        }
    }

    public static void main(String[] args) {
        String sn = "UserEntity";
        System.out.println(StringUtils.uncapitalize(sn));
    }



}
